home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / sendmail / sendmail-5.65c+IDA-1.4.4.1 / src / daemon.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-08-12  |  24.3 KB  |  1,080 lines

  1. /*
  2.  * Copyright (c) 1983 Eric P. Allman
  3.  * Copyright (c) 1988 Regents of the University of California.
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms are permitted provided
  7.  * that: (1) source distributions retain this entire copyright notice and
  8.  * comment, and (2) distributions including binaries display the following
  9.  * acknowledgement:  ``This product includes software developed by the
  10.  * University of California, Berkeley and its contributors'' in the
  11.  * documentation or other materials provided with the distribution and in
  12.  * all advertising materials mentioning features or use of this software.
  13.  * Neither the name of the University nor the names of its contributors may
  14.  * be used to endorse or promote products derived from this software without
  15.  * specific prior written permission.
  16.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  17.  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  18.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  19.  */
  20.  
  21. #include "sendmail.h"
  22. #include <errno.h>
  23. #ifdef ISC
  24. # include <net/errno.h>
  25. #endif /* ISC */
  26.  
  27. #ifndef lint
  28. # ifdef DAEMON
  29. static char sccsid[] = "@(#)daemon.c    5.36 (Berkeley) 6/1/90 (with daemon mode)";
  30. static char rcsid[] = "@(#)$Id: daemon.c,v 5.36.0.27 1991/08/12 17:52:32 paul Exp $ (with daemon mode)";
  31. # else /* !DAEMON */
  32. static char sccsid[] = "@(#)daemon.c    5.36 (Berkeley) 6/1/90 (without daemon mode)";
  33. static char rcsid[] = "@(#)$Id: daemon.c,v 5.36.0.27 1991/08/12 17:52:32 paul Exp $ (without daemon mode)";
  34. # endif /* DAEMON */
  35. #endif /* not lint */
  36.  
  37. int la;    /* load average */
  38.  
  39. #ifdef VMUNIX
  40. # include <netdb.h>
  41. # ifdef ISC
  42.   typedef short pid_t;
  43. # endif /* ISC */
  44. # include <sys/wait.h>
  45. # include <sys/stat.h>
  46. # ifdef NAMED_BIND
  47. #  include <arpa/nameser.h>
  48. #  include <resolv.h>
  49. # endif /* NAMED_BIND */
  50.  
  51. struct sockaddr_in    SendmailAddress; /* internet address of sendmail */
  52.  
  53. #endif /* VMUNIX */
  54.  
  55. #ifdef DAEMON
  56.  
  57. /*
  58. **  DAEMON.C -- routines to use when running as a daemon.
  59. **
  60. **    This entire file is highly dependent on the 4.2 BSD
  61. **    interprocess communication primitives.  No attempt has
  62. **    been made to make this file portable to Version 7,
  63. **    Version 6, MPX files, etc.  If you should try such a
  64. **    thing yourself, I recommend chucking the entire file
  65. **    and starting from scratch.  Basic semantics are:
  66. **
  67. **    getrequests()
  68. **        Opens a port and initiates a connection.
  69. **        Returns in a child.  Must set InChannel and
  70. **        OutChannel appropriately.
  71. **    clrdaemon()
  72. **        Close any open files associated with getting
  73. **        the connection; this is used when running the queue,
  74. **        etc., to avoid having extra file descriptors during
  75. **        the queue run and to avoid confusing the network
  76. **        code (if it cares).
  77. **    makeconnection(host, port, outfile, infile)
  78. **        Make a connection to the named host on the given
  79. **        port.  Set *outfile and *infile to the files
  80. **        appropriate for communication.  Returns zero on
  81. **        success, else an exit status describing the
  82. **        error.
  83. **    maphostname(hbuf, hbufsize)
  84. **        Convert the entry in hbuf into a canonical form.  It
  85. **        may not be larger than hbufsize.
  86. **
  87. **    mapinit(c)
  88. **        Open and initialize a dbm database.  Reopen if our current
  89. **        file descriptor is out of date.
  90. **
  91. **    mapkey(c, key, argval, argsiz)
  92. **        Search a database for a match to the given key, sprintf'ing
  93. **        the argument through the result if found.
  94. */
  95. /*
  96. **  GETREQUESTS -- open mail IPC port and get requests.
  97. **
  98. **    Parameters:
  99. **        none.
  100. **
  101. **    Returns:
  102. **        none.
  103. **
  104. **    Side Effects:
  105. **        Waits until some interesting activity occurs.  When
  106. **        it does, a child is created to process it, and the
  107. **        parent waits for completion.  Return from this
  108. **        routine is always in the child.  The file pointers
  109. **        "InChannel" and "OutChannel" should be set to point
  110. **        to the communication channel.
  111. */
  112.  
  113. int    DaemonSocket    = -1;        /* fd describing socket */
  114.  
  115. void
  116. getrequests()
  117. {
  118.     int t;
  119.     register struct servent *sp;
  120.     int on = 1;
  121.  
  122.     /*
  123.     **  Set up the address for the mailer.
  124.     */
  125.  
  126.     sp = getservbyname("smtp", "tcp");
  127.     if (sp == NULL)
  128.     {
  129.         syserr("server \"smtp\" unknown");
  130.         goto severe;
  131.     }
  132.     SendmailAddress.sin_family = AF_INET;
  133.     SendmailAddress.sin_addr.s_addr = INADDR_ANY;
  134.     SendmailAddress.sin_port = sp->s_port;
  135.  
  136.     /*
  137.     **  Try to actually open the connection.
  138.     */
  139.  
  140.     if (tTd(15, 1))
  141.         printf("getrequests: port 0x%x\n", SendmailAddress.sin_port);
  142.  
  143.     /* get a socket for the SMTP connection */
  144.     DaemonSocket = socket(AF_INET, SOCK_STREAM, 0);
  145.     if (DaemonSocket < 0)
  146.     {
  147.         /* probably another daemon already */
  148.         syserr("getrequests: can't create socket");
  149.       severe:
  150. # ifdef LOG
  151.         if (LogLevel > 0)
  152.             syslog(LOG_ALERT, "cannot get connection");
  153. # endif /* LOG */
  154.         finis();
  155.     }
  156.  
  157.     /* turn on network debugging? */
  158.     if (tTd(15, 15))
  159.         (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof on);
  160.  
  161.     (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof on);
  162.     (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof on);
  163.  
  164.     if (bind(DaemonSocket,
  165.         (struct sockaddr *) &SendmailAddress, sizeof SendmailAddress) < 0)
  166.     {
  167.         syserr("getrequests: cannot bind");
  168.         (void) close(DaemonSocket);
  169.         goto severe;
  170.     }
  171.     if (listen(DaemonSocket, 10) < 0)
  172.     {
  173.         syserr("getrequests: cannot listen");
  174.         (void) close(DaemonSocket);
  175.         goto severe;
  176.     }
  177.  
  178. # ifdef SIGCHLD
  179.     (void) signal(SIGCHLD, reapchild);
  180. # endif /* SIGCHLD */
  181.  
  182.     if (tTd(15, 1))
  183.         printf("getrequests: %d\n", DaemonSocket);
  184.  
  185. # ifdef _PATH_SENDMAILPID
  186.     (void) WritePid();
  187. # endif /* _PATH_SENDMAILPID */
  188.  
  189.     for (;;)
  190.     {
  191.         register int pid;
  192.         auto int lotherend;
  193.         extern int RefuseLA;
  194.  
  195.         /*
  196.          * see if we are rejecting connections
  197.          */
  198.         while ((la = getla()) > RefuseLA)
  199.         {
  200.             setproctitle("rejecting connections: load average: %.2f", (double)la);
  201.             Xsleep (5);
  202.         }
  203.         setproctitle("Waiting for connection");
  204.  
  205.         do
  206.         {
  207.             errno = 0;
  208.             lotherend = sizeof RealHostAddr;
  209.             t = accept(DaemonSocket,
  210.                 (struct sockaddr *) &RealHostAddr, &lotherend);
  211.         } while (t < 0 && errno == EINTR);
  212.         if (t < 0)
  213.         {
  214.             syserr("getrequests: accept");
  215.             Xsleep(5);
  216.             continue;
  217.         }
  218.  
  219.         /*
  220.         **  Create a subprocess to process the mail.
  221.         */
  222.  
  223.         if (tTd(15, 2))
  224.             printf("getrequests: forking (fd = %d)\n", t);
  225.  
  226.         pid = fork();
  227.         if (pid > 0 && tTd(4, 2))
  228.             printf("getrequests: forking (pid = %d)\n", pid);
  229.         if (pid < 0)
  230.         {
  231.             syserr("daemon: cannot fork");
  232.             Xsleep(10);
  233.             (void) close(t);
  234.             continue;
  235.         }
  236.  
  237.         if (pid == 0)
  238.         {
  239.             register struct hostent *hp;
  240.             char buf[MAXNAME];
  241.  
  242.             /*
  243.             **  CHILD -- return to caller.
  244.             **    Collect verified idea of sending host.
  245.             **    Verify calling user id if possible here.
  246.             */
  247.  
  248. # ifdef SIGCHLD
  249.             (void) signal(SIGCHLD, SIG_DFL);
  250. # endif /* SIGCHLD */
  251.  
  252.             /* determine host name */
  253.             hp = gethostbyaddr((char *) &RealHostAddr.sin_addr, sizeof RealHostAddr.sin_addr, AF_INET);
  254.             if (hp != NULL)
  255.                 (void) strcpy(buf, hp->h_name);
  256.             else
  257.             {
  258.                 /* produce a dotted quad */
  259.                 (void) sprintf(buf, "[%s]",
  260.                     inet_ntoa(RealHostAddr.sin_addr));
  261.             }
  262.  
  263.             /* should we check for illegal connection here? XXX */
  264.  
  265.             RealHostName = newstr(buf);
  266.  
  267.             (void) close(DaemonSocket);
  268.             InChannel = fdopen(t, "r");
  269.             OutChannel = fdopen(dup(t), "w");
  270.             if (tTd(15, 2))
  271.                 printf("getreq: returning\n");
  272. # ifdef LOG
  273.             if (LogLevel > 11)
  274.                 syslog(LOG_DEBUG, "connected, pid=%d", getpid());
  275. # endif /* LOG */
  276.             return;
  277.         }
  278.  
  279.         /* close the port so that others will hang (for a while) */
  280.         (void) close(t);
  281.     }
  282.     /*NOTREACHED*/
  283. }
  284. /*
  285. **  CLRDAEMON -- reset the daemon connection
  286. **
  287. **    Parameters:
  288. **        none.
  289. **
  290. **    Returns:
  291. **        none.
  292. **
  293. **    Side Effects:
  294. **        releases any resources used by the passive daemon.
  295. */
  296.  
  297. void
  298. clrdaemon()
  299. {
  300.     if (DaemonSocket >= 0)
  301.         (void) close(DaemonSocket);
  302.     DaemonSocket = -1;
  303. }
  304. #endif /* DAEMON */
  305. #ifdef VMUNIX
  306. /*
  307. **  MAKECONNECTION -- make a connection to an SMTP socket on another machine.
  308. **
  309. **    Parameters:
  310. **        host -- the name of the host.
  311. **        port -- the port number to connect to.
  312. **        outfile -- a pointer to a place to put the outfile
  313. **            descriptor.
  314. **        infile -- ditto for infile.
  315. **
  316. **    Returns:
  317. **        An exit code telling whether the connection could be
  318. **            made and if not why not.
  319. **
  320. **    Side Effects:
  321. **        none.
  322. */
  323.  
  324. int
  325. makeconnection(host, port, outfile, infile)
  326.     const char *host;
  327.     u_short port;
  328.     FILE **outfile;
  329.     FILE **infile;
  330. {
  331.     register int i = 0;
  332.     register int s;
  333.     register struct hostent *hp = (struct hostent *)NULL;
  334.     int sav_errno = 0;
  335. # ifdef NAMED_BIND
  336.     extern int h_errno;
  337.  
  338.     /*
  339.     **  Don't do recursive domain searches.  An example why not:
  340.     **  Machine cerl.cecer.army.mil has a UUCP connection to
  341.     **  osiris.cso.uiuc.edu.  Also at UIUC is a machine called
  342.     **  uinova.cerl.uiuc.edu that accepts mail for the its parent domain
  343.     **  cerl.uiuc.edu.  Sending mail to cerl!user with recursion on
  344.     **  will select cerl.uiuc.edu which maps to uinova.cerl.uiuc.edu.
  345.     **  We leave RES_DEFNAMES on so single names in the current domain
  346.     **  still work.
  347.     **
  348.     **  Paul Pomes, CSO, UIUC    17-Oct-88
  349.     */
  350.  
  351.     _res.options &= (~RES_DNSRCH & 0xffff);
  352.  
  353.     /*
  354.     **  Set up the address for the mailer.
  355.     **    Accept "[a.b.c.d]" syntax for host name.
  356.     */
  357.  
  358.     h_errno = 0;
  359. # endif /* NAMED_BIND */
  360.     errno = 0;
  361.  
  362.     if (host[0] == '[')
  363.     {
  364.         unsigned long hid = INADDR_NONE;
  365.         register char *p = index(host, ']');
  366.  
  367.         if (p != NULL)
  368.         {
  369.             *p = '\0';
  370.             hid = inet_addr(&host[1]);
  371.             *p = ']';
  372.         }
  373.         if (p == NULL || hid == INADDR_NONE)
  374.         {
  375.             usrerr("Invalid numeric domain spec \"%s\"", host);
  376.             return (EX_NOHOST);
  377.         }
  378.         SendmailAddress.sin_addr.s_addr = hid;
  379.     }
  380.     else
  381.     {
  382.         hp = gethostbyname(host);
  383.         if (hp == NULL)
  384.         {
  385. # ifdef NAMED_BIND
  386.             if (errno == ETIMEDOUT || h_errno == TRY_AGAIN)
  387.                 return (EX_TEMPFAIL);
  388.  
  389.             /* if name server is specified, assume temp fail */
  390.             if (errno == ECONNREFUSED && UseNameServer)
  391.                 return (EX_TEMPFAIL);
  392. # endif /* NAMED_BIND */
  393.  
  394.             /*
  395.             **  XXX Should look for mail forwarder record here
  396.             **  XXX if (h_errno == NO_ADDRESS).
  397.             */
  398.  
  399.             return (EX_NOHOST);
  400.         }
  401.         bcopy(hp->h_addr, (char *) &SendmailAddress.sin_addr, hp->h_length);
  402.         i = 1;
  403.     }
  404.  
  405.     /*
  406.     **  Determine the port number.
  407.     */
  408.  
  409.     if (port != 0)
  410.         SendmailAddress.sin_port = htons(port);
  411.     else
  412.     {
  413.         register struct servent *sp = getservbyname("smtp", "tcp");
  414.  
  415.         if (sp == NULL)
  416.         {
  417.             syserr("makeconnection: server \"smtp\" unknown");
  418.             return (EX_OSFILE);
  419.         }
  420.         SendmailAddress.sin_port = sp->s_port;
  421.     }
  422.  
  423.     /*
  424.     **  Try to actually open the connection.
  425.     */
  426.  
  427. again:
  428.     if (tTd(16, 1))
  429.         printf("makeconnection (%s [%s])\n", host,
  430.             inet_ntoa(SendmailAddress.sin_addr));
  431.  
  432.     s = socket(AF_INET, SOCK_STREAM, 0);
  433.     if (s < 0)
  434.     {
  435.         syserr("makeconnection: no socket");
  436.         sav_errno = errno;
  437.         goto failure;
  438.     }
  439.  
  440.     if (tTd(16, 1))
  441.         printf("makeconnection: %d\n", s);
  442.  
  443.     /* turn on network debugging? */
  444.     if (tTd(16, 14))
  445.     {
  446.         int on = 1;
  447.         (void) setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof on);
  448.     }
  449.     if (CurEnv->e_xfp != NULL)
  450.         (void) fflush(CurEnv->e_xfp);        /* for debugging */
  451.     errno = 0;                    /* for debugging */
  452.     SendmailAddress.sin_family = AF_INET;
  453.     if (connect(s,
  454.         (struct sockaddr *) &SendmailAddress, sizeof SendmailAddress) < 0)
  455.     {
  456.         switch (errno)
  457.         {
  458.             case ETIMEDOUT:
  459.             case EHOSTUNREACH:
  460.             case ENETUNREACH:
  461.             /* there are others, I'm sure..... */
  462.             if (sav_errno == 0)
  463.                 sav_errno = errno;
  464.             break;
  465.  
  466.             default:
  467.             sav_errno = errno;
  468.         }
  469.         (void) close(s);
  470. # ifdef NAMED_BIND
  471.         if (hp && hp->h_addr_list[i])
  472.         {
  473.             bcopy(hp->h_addr_list[i++],
  474.                 (char *)&SendmailAddress.sin_addr, hp->h_length);
  475.             goto again;
  476.         }
  477. # endif /* NAMED_BIND */
  478.  
  479.         /* failure, decide if temporary or not */
  480.     failure:
  481.         errno = sav_errno;
  482.         switch (errno)
  483.         {
  484.           case EISCONN:
  485.           case ETIMEDOUT:
  486.           case EINPROGRESS:
  487.           case EALREADY:
  488.           case EADDRINUSE:
  489.           case EHOSTDOWN:
  490.           case ENETDOWN:
  491.           case ENETRESET:
  492.           case ENOBUFS:
  493.           case ECONNREFUSED:
  494.           case ECONNRESET:
  495.           case EHOSTUNREACH:
  496.           case ENETUNREACH:
  497.             /* there are others, I'm sure..... */
  498.             return (EX_TEMPFAIL);
  499.  
  500.           case EPERM:
  501.             /* why is this happening? */
  502.             syserr("makeconnection: funny failure, addr=%lx, port=%x",
  503.                 SendmailAddress.sin_addr.s_addr, SendmailAddress.sin_port);
  504.             return (EX_TEMPFAIL);
  505.  
  506.           default:
  507.             {
  508.                 message(Arpa_Info, "%s", errstring(sav_errno));
  509.                 return (EX_UNAVAILABLE);
  510.             }
  511.         }
  512.     }
  513.  
  514.     /* connection ok, put it into canonical form */
  515.     *infile = fdopen(s, "r");
  516.     *outfile = fdopen(dup(s), "w");
  517.  
  518.     /* Necessary to catch leaks */
  519.     if (*outfile == NULL || *infile == NULL)
  520.     {
  521.         syserr("makeconnection: *outfile or *infile NULL");
  522.         return (EX_TEMPFAIL);
  523.     }
  524.     else
  525.         return (EX_OK);
  526. }
  527. /*
  528. **  MYHOSTNAME -- return the name of this host.
  529. **
  530. **    Parameters:
  531. **        hostbuf -- a place to return the name of this host.
  532. **        size -- the size of hostbuf.
  533. **
  534. **    Returns:
  535. **        A list of aliases for this host.
  536. **
  537. **    Side Effects:
  538. **        none.
  539. */
  540.  
  541. char **
  542. myhostname(hostbuf, size)
  543.     char hostbuf[];
  544.     int size;
  545. {
  546.     struct hostent *hp;
  547.  
  548.     if (gethostname(hostbuf, size) < 0)
  549.         (void) strcpy(hostbuf, "localhost");
  550. # ifdef NAMED_BIND
  551.     while ((hp = gethostbyname(hostbuf)) == NULL)
  552.     {
  553.         setproctitle("gethostbyname(%s) failed, sleeping", hostbuf);
  554.         Xsleep(10);
  555.     }
  556. # else /* !NAMED_BIND */
  557. #  ifdef sun
  558.     /*
  559.      *    An ugly hack.
  560.      *    This routine is mainly called to assign a default value
  561.      *    to $w .  As such it must be called before the config file
  562.      *    is processed.  On Sun systems this involves calls to some
  563.      *    of the yp lookup routines.  They apparently leave state
  564.      *    information lying around which is inconsistent with the
  565.      *    use of frozen configurations.  Since the standard Sun
  566.      *    setup leaves hostnames unqualified anyway, omitting the
  567.      *    gethostbyname() call should have little effect.
  568.      */
  569.  
  570.     hp = NULL;
  571. #  else /* !sun */
  572.     hp = gethostbyname(hostbuf);
  573. #  endif /* sun */
  574. # endif /* NAMED_BIND */
  575.     if (hp != NULL)
  576.     {
  577.         (void) strcpy(hostbuf, hp->h_name);
  578.         return (hp->h_aliases);
  579.     }
  580.     else
  581.         return (NULL);
  582. }
  583.  
  584. /*
  585. **  MAPHOSTNAME -- turn a hostname into canonical form
  586. **
  587. **    Parameters:
  588. **        hbuf -- a buffer containing a hostname.
  589. **        hbsize -- the size of hbuf.
  590. **
  591. **    Returns:
  592. **        An exit code telling if the hostname was found and
  593. **        canonicalized.
  594. **
  595. **    Side Effects:
  596. **        Looks up the host specified in hbuf.  If it is not
  597. **        the canonical name for that host, replace it with
  598. **        the canonical name.  If the name is unknown, or it
  599. **        is already the canonical name, leave it unchanged.
  600. **/
  601. bool
  602. maphostname(hbuf, hbsize)
  603.     char *hbuf;
  604.     int hbsize;
  605. {
  606.     register struct hostent *hp;
  607.     static char tmphbuf[MAXNAME];
  608.  
  609.     /*
  610.      * If first character is a bracket, then it is an address
  611.      * lookup.  Address is copied into a temporary buffer to
  612.      * strip the brackets and to preserve hbuf if address is
  613.      * unknown.
  614.      */
  615.     if (*hbuf == '[')
  616.     {
  617.         u_long in_addr;
  618.  
  619.         (void) strncpy(tmphbuf, hbuf+1, strlen(hbuf)-2);
  620.         tmphbuf[strlen(hbuf)-2]='\0';
  621.         in_addr = inet_addr(tmphbuf);
  622.         hp = gethostbyaddr((char *) &in_addr, sizeof(struct in_addr), AF_INET);
  623.     }
  624.     else
  625.     {
  626.         register int ret;
  627.  
  628. # ifdef NAMED_BIND
  629.         /*
  630.         ** See note in makeconnection() above for why we disable
  631.         ** recursive domain matching.  -pbp
  632.         */
  633.         _res.options &= (~RES_DNSRCH & 0xffff);
  634.  
  635.         /*
  636.         ** But make sure default domain qualification is enabled -
  637.         ** it may have been disabled in deliver.c.  -nr
  638.         */
  639.         _res.options |= RES_DEFNAMES ;
  640. # endif /* NAMED_BIND */
  641.  
  642.         hp = gethostbyname(hbuf);
  643.         if (hp == NULL)
  644.         {
  645.             /* try lowercase version */
  646.             (void) strcpy(tmphbuf, hbuf);
  647.             (void) makelower(tmphbuf);
  648.             /* Could be just an MX record; look for anything */
  649.             ret = getcanonname(tmphbuf,sizeof(tmphbuf));
  650.             if (ret != TRUE)
  651.             {
  652.                 if (tTd(9, 1))
  653.                     printf("maphostname(%s, %d) => %.*s\n",
  654.                         hbuf, hbsize, hbsize-1,
  655.                         hp ? hp->h_name : "NOT_FOUND");
  656.                 return FALSE;
  657.             }
  658.             (void) strcpy(hbuf,tmphbuf);
  659.             return TRUE;
  660.         }
  661.     }
  662.     if (tTd(9, 1))
  663.         printf("maphostname(%s, %d) => %.*s\n",
  664.             hbuf, hbsize, hbsize-1, hp ? hp->h_name : "NOT_FOUND");
  665.     if (hp == NULL)
  666.         return FALSE;
  667.  
  668.     if ((int)(strlen(hp->h_name)) >= hbsize)
  669.         hp->h_name[hbsize - 1] = '\0';
  670.     (void) strcpy(hbuf, hp->h_name);
  671.     return TRUE;
  672. }
  673.  
  674. #else /* !VMUNIX */
  675. /* code for systems without sophisticated networking */
  676.  
  677. # ifdef HAS_UNAME
  678. #  include <sys/utsname.h>
  679. # endif /* HAS_UNAME */
  680.  
  681. /*
  682. **  MYHOSTNAME -- stub version for case of no gethostent(3N) code.
  683. **
  684. **    Can't convert to upper case here because might be a UUCP name.
  685. **
  686. **    Mark, you can change this to be anything you want......
  687. */
  688.  
  689. char **
  690. myhostname(hostbuf, size)
  691.     char hostbuf[];
  692.     int size;
  693. {
  694.     register FILE *f;
  695. # ifdef HAS_UNAME
  696.     struct    utsname    utsname;
  697. # endif /* HAS_UNAME */
  698.  
  699.     hostbuf[0] = '\0';
  700. # ifdef HAS_UNAME
  701.     if (uname(&utsname) != -1)
  702.         strncpy(hostbuf, utsname.nodename, min(8, size-1));
  703. # else /* !HAS_UNAME */
  704.     f = fopen("/usr/include/whoami", "r");
  705.     if (f != NULL)
  706.     {
  707.         (void) fgets(hostbuf, size, f);
  708.         fixcrlf(hostbuf, TRUE);
  709.         (void) fclose(f);
  710.     }
  711. # endif /* HAS_UNAME */
  712.     if (hostbuf[0])
  713.     {
  714.         static char *alias[2];
  715.         /*
  716.          * an alias is nodename.uucp
  717.          * this is an alias and the nodename is the canonical form
  718.          * because ".uucp" isn't an official top-level domain.
  719.          */
  720.  
  721.         if (alias[0])
  722.             free(alias[0]); /* in case called more than once */
  723.         alias[0] = (char *)xalloc(strlen(hostbuf)+6);
  724.         strcpy(alias[0], hostbuf);
  725.         strcat(alias[0], ".uucp");
  726.         alias[1] = (char *)NULL;
  727.         return(alias);
  728.     }
  729.     else
  730.         return (NULL);
  731. }
  732.  
  733. #endif /* VMUNIX */
  734. /*
  735. **  MAPINIT -- Open and (re)initialize a dbm database
  736. **
  737. **    Parameters:
  738. **        c -- the (one character) name of the database
  739. **
  740. **    Returns:
  741. **        An exit code telling if we could open the database.
  742. **
  743. */
  744. #if defined(NDBM) || defined(OTHERDBM)
  745. bool
  746. mapinit(c)
  747.     char c;
  748. {
  749.     struct stat stb;
  750.     struct dbm_table *db;
  751.     int k;
  752.     char buf[MAXNAME];
  753.  
  754.     db = &DbmTab[c & 0177];
  755.  
  756.     if (db->db_name == NULL)
  757.     {
  758.         syserr("database '%c' has not been defined", c);
  759.         return FALSE;
  760.     }
  761.  
  762. # ifdef YPMARK
  763.     /*
  764.      * Yellow pages are always supposed to be ready
  765.      */
  766.     if (db->db_name[0] == YPMARK)
  767.         return TRUE;
  768. # endif /* YPMARK */
  769.  
  770.     /*
  771.      * Have we already (unsuccessfully) tried to open it?
  772.      */
  773.     if (db->db_dbm == DB_NOSUCHFILE)
  774.     {
  775.         if (tTd(60, 1))
  776.             printf("mapinit(%c) => NO_FILE\n", c);
  777.         return FALSE;
  778.     }
  779.  
  780.     /*
  781.      * If it already is open, check if it has been changed.
  782.      */
  783.     (void) sprintf(buf, "%s%s", db->db_name, DB_DIREXT);
  784.     if (db->db_dbm != DB_NOTYETOPEN)
  785.     {
  786.         if (stat(buf, &stb) < 0 && (Xsleep(30), stat(buf, &stb) < 0))
  787.         {
  788.             syserr("somebody removed %s for db '%c'", buf, c);
  789.             db->db_dbm = DB_NOSUCHFILE;
  790.             if (tTd(60, 1))
  791.                 printf("mapinit(%c) => FILE_REMOVED\n", c);
  792.             return FALSE;
  793.         }
  794.         if (db->db_mtime != stb.st_mtime)
  795.         {
  796.             if (tTd(60, 1))
  797.                 printf("database '%c' [%s] has changed; reopening it\n",
  798.                     c, db->db_name);
  799.             (void) dbm_close(db->db_dbm);
  800.             db->db_dbm = DB_NOTYETOPEN;
  801.         }
  802.     }
  803.  
  804.     /*
  805.      * Initialize database if not already open (r/w for aliases iff init)
  806.      */
  807.     if (db->db_dbm == DB_NOTYETOPEN)
  808.     {
  809.         db->db_dbm = dbm_open(db->db_name,
  810.             (OpMode == MD_INITALIAS && c == DB_ALIAS)
  811.             ? O_RDWR : O_RDONLY, 0);
  812.         if (db->db_dbm == DB_NOSUCHFILE)
  813.         {
  814.             /* try once more */
  815.             Xsleep(30);
  816.             db->db_dbm = dbm_open(db->db_name,
  817.                 (OpMode == MD_INITALIAS && c == DB_ALIAS)
  818.                 ? O_RDWR : O_RDONLY, 0);
  819.         }
  820.         if (db->db_dbm == DB_NOSUCHFILE)
  821.         {
  822.             syserr("can't open database '%c' [%s]", c, db->db_name);
  823.             if (tTd(60, 1))
  824.                 printf("mapinit(%c) => CAN'T OPEN %s\n",
  825.                     c, db->db_name);
  826.             return FALSE;
  827.         }
  828.         if (stat(buf, &stb) < 0 && (Xsleep(30), stat(buf, &stb) < 0))
  829.         {
  830.             syserr("can't stat %s", buf);
  831.             if (tTd(60, 1))
  832.                 printf("mapinit(%c) => FILE_REMOVED\n", c);
  833.             return FALSE;
  834.         }
  835.         db->db_mtime = stb.st_mtime;
  836.  
  837. # ifndef GDBM
  838.         /*
  839.          * Make sure the database isn't being updated
  840.          */
  841.         if (flock(dbm_dirfno(db->db_dbm),
  842.             ((OpMode == MD_INITALIAS && c == DB_ALIAS) ? LOCK_EX : LOCK_SH) | LOCK_NB) < 0)
  843.         {
  844.             if (errno == EWOULDBLOCK || errno == EAGAIN)
  845.             {
  846.                 if (tTd(60, 1))
  847.                     printf("%s%s is locked, waiting...\n",
  848.                         db->db_name, DB_DIREXT);
  849.                 (void) flock(dbm_dirfno(db->db_dbm),
  850.                         ((OpMode == MD_INITALIAS && c == DB_ALIAS) ? LOCK_EX : LOCK_SH));
  851.             }
  852.             else
  853.                 syserr("flock failed for db %c [%s], fd %d",
  854.                     c, db->db_name, dbm_dirfno(db->db_dbm));
  855.         }
  856.         (void) flock(dbm_dirfno(db->db_dbm), LOCK_UN);
  857. # endif /* !GDBM */
  858.     }
  859.     return TRUE;
  860. }
  861. /*
  862. **  MAPKEY -- Search a dbm database.
  863. **
  864. **    Search the named database using the given key.  If
  865. **    a result is found, sprintf the argument through the
  866. **    result back into the key and return TRUE;
  867. **    otherwise return FALSE and do nothing.
  868. **
  869. **    Keysize may also be given as zero, in which case the
  870. **    sprintf'ed result is returned if the key matched.
  871. **
  872. **    Parameters:
  873. **        c -- the database
  874. **        key -- search string
  875. **        keysiz -- size of key
  876. **        arg -- sprintf argument
  877. **
  878. **    Returns:
  879. **        An exit code telling if there was a match.
  880. **
  881. **    Side Effects:
  882. **        The key is rewritten to reflect what was found
  883. **        in the database.
  884. */
  885.  
  886. char *
  887. mapkey(c, key, keysiz, arg)
  888.     char c;
  889.     const char *arg;
  890.     char *key;
  891.     int keysiz;
  892. {
  893.     struct dbm_table *db;
  894.     XDATUM dkey, result;
  895.     char *lowkey;
  896. # ifdef YPMARK
  897.     static char *yp_domain = NULL;
  898. # endif /* YPMARK */
  899.  
  900.     db = &DbmTab[c & 0177];
  901.  
  902.     if (tTd(60, 1))
  903.         printf("mapkey('%c', \"%s\", \"%s\") => ",
  904.             c, key, arg ? arg : "--");
  905.  
  906.     /*
  907.      * Init the database; return if failure
  908.      */
  909.     if (!mapinit(c))
  910.         return NULL;
  911.  
  912.     /*
  913.      * Normalize key (ie turn it to lowercase)
  914.      */
  915.     lowkey = newstr(key);
  916.     (void) makelower(lowkey);
  917.  
  918. # ifdef YPMARK
  919.     /*
  920.      * Test for yellow page database first
  921.      */
  922.     if (db->db_name[0] == YPMARK)
  923.     {
  924.         if (yp_domain == NULL)
  925.             (void) yp_get_default_domain(&yp_domain);
  926.  
  927.     /*
  928.      * We include the null after the string, but Sun doesn't
  929.      */
  930.         if (
  931.             yp_match(yp_domain, &db->db_name[1], key,
  932.             strlen(key)+1, &result.dptr, &result.dsize) != 0 &&
  933.             yp_match(yp_domain, &db->db_name[1], key,
  934.             strlen(key), &result.dptr, &result.dsize) != 0 &&
  935.             yp_match(yp_domain, &db->db_name[1], lowkey,
  936.             strlen(key)+1, &result.dptr, &result.dsize) != 0 &&
  937.             yp_match(yp_domain, &db->db_name[1], lowkey,
  938.             strlen(key), &result.dptr, &result.dsize) != 0)
  939.             result.dptr = NULL;
  940.  
  941.         /* smash newline if supplied */
  942.         else if (result.dptr[result.dsize] == '\n')
  943.             result.dptr[result.dsize] = '\0';
  944.     }
  945.     else
  946.     {
  947. # endif /* YPMARK */
  948.         /*
  949.          * Go look for matching dbm entry
  950.          */
  951.         dkey.dsize = strlen(key);
  952.         dkey.dptr = key;
  953.  
  954.         /* verbatim key */
  955.         result = dbm_fetch(db->db_dbm, dkey);
  956.         if (result.dptr == (char *)NULL)
  957.         {
  958.             /* try null-terminated version of given key */
  959.             dkey.dsize += 1;
  960.             result = dbm_fetch(db->db_dbm, dkey);
  961.             if (result.dptr == (char *)NULL)
  962.             {
  963.                 /* use lower case key */
  964.                 dkey.dsize -= 1;
  965.                 dkey.dptr = lowkey;
  966.                 result = dbm_fetch(db->db_dbm, dkey);
  967.                 if (result.dptr == (char *)NULL)
  968.                 {
  969.                     /* try as null-terminated lower case */
  970.                     dkey.dsize += 1;
  971.                     result = dbm_fetch(db->db_dbm, dkey);
  972.                 }
  973.             }
  974.         }
  975. # ifdef YPMARK
  976.     }
  977. # endif /* YPMARK */
  978.  
  979.     free(lowkey);
  980.     /*
  981.      * Well, were we successful?
  982.      */
  983.     if (result.dptr == NULL)
  984.     {
  985.         if (tTd(60, 1))
  986.             printf("NOT_FOUND\n");
  987.         return NULL;
  988.     }
  989.  
  990.     /*
  991.      * Yes, rewrite result if sprintf arg was given.
  992.      */
  993.     if (arg == NULL)
  994.     {
  995.         lowkey = dbm_newstr(result);
  996.         if (tTd(60, 2))
  997.             printf("[ no arg ] %s\n", lowkey);
  998.     }
  999.     else
  1000.     {
  1001.         char *fmt, *percent;
  1002.         bool need_sprintf = FALSE;
  1003.  
  1004.         fmt = dbm_newstr(result);
  1005.         percent = fmt;
  1006.         while ((percent = index(percent, '%')) != NULL)
  1007.         {
  1008.             if (*(++percent) == 's')
  1009.             {
  1010.                 need_sprintf = TRUE;
  1011.                 break;
  1012.             }
  1013.             else if (*percent == '%') /* %% */
  1014.                 ++percent;
  1015.         }
  1016.         if (need_sprintf)
  1017.         {
  1018.             /* expect an arg */
  1019.             lowkey = xalloc(result.dsize + strlen(arg));
  1020.             (void) sprintf(lowkey, fmt, arg);
  1021.             if (tTd(60, 2))
  1022.                 printf("[%s] %s => %s\n", fmt, arg, lowkey);
  1023.             free(fmt);
  1024.         }
  1025.         else
  1026.         {
  1027.             /* keep the allocated string */
  1028.             lowkey = fmt;
  1029.             if (tTd(60, 2))
  1030.                 printf("[ no arg expected ] %s\n", lowkey);
  1031.         }
  1032.     }
  1033.     if ((int)(strlen(lowkey)) > MAXLINE)
  1034.     {
  1035.         syserr("mapkey: strlen(lowkey) (%d) > %d\n",
  1036.             strlen(lowkey), MAXLINE);
  1037. # ifdef LOG
  1038.         syslog(LOG_ALERT, "mapkey: strlen(lowkey) (%d) > %d\n",
  1039.             strlen(lowkey), MAXLINE);
  1040. # endif /* LOG */
  1041.     }
  1042.  
  1043.     /*
  1044.      * if keysiz is zero, that means we should return a string from
  1045.      * the heap
  1046.      */
  1047.     if (keysiz == 0)
  1048.         key = lowkey;
  1049.     else
  1050.     {
  1051.         if ((int)(strlen(lowkey)+1) > keysiz)
  1052.         {
  1053.             syserr("mapkey: result \"%s\" too long after expansion\n",
  1054.                 lowkey);
  1055.             lowkey[keysiz-1] = '\0';
  1056.         }
  1057.         (void) strcpy(key, lowkey);
  1058.         free(lowkey);
  1059.     }
  1060.     if (tTd(60, 1))
  1061.         printf("%s\n", key);
  1062.  
  1063.     return (key);
  1064. }
  1065.  
  1066. #else /* !NDBM && !OTHERDBM */
  1067.  
  1068. /* should really read the table into the stab instead */
  1069. /*ARGSUSED*/
  1070. char *
  1071. mapkey(db, key, keysiz, arg)
  1072.     char db;
  1073.     const char *arg;
  1074.     char *key;
  1075.     int keysiz;
  1076. {
  1077.     return NULL;
  1078. }
  1079. #endif /* NDBM || OTHERDBM */
  1080.